
#include <dm/export.hpp>
#ifndef DM_API_SCADA
#define DM_API_SCADA DM_API_EXPORT
#endif

#include <dm/scada/signals/status_mgr.hpp>
#include <dm/os/log/logger.hpp>
#include <dm/os/db/db.hpp>
#include <dm/os/db/resultset.hpp>
#include <dm/env/cfg.hpp>
#include <dm/scoped_ptr.hpp>

namespace dm{
namespace scada{
namespace signals{

static const char* logModule = "CStatusMgr.signals.scada.dm";

/**
 * 数据加载器类
*/
class CLoader:public CStatusMgr::buf_mgr_t::CLoader{
public:
    CLoader():m_maxId(-1){
        dm::env::CCfg& cfg = dm::env::CCfg::ins();

        m_db = dm::os::createDb(cfg.scada_dbName().c_str(),cfg.scada_dbHost().c_str(),cfg.scada_dbEngine().c_str(),cfg.scada_dbPort());
        m_db->connect(cfg.scada_dbUsr().c_str(),cfg.scada_dbPwd().c_str());
    }

    bool createTables(){
    	switch( m_db->dbType() ){
    	case dm::os::CDb::DtSqlite:
    		return m_db->exec("CREATE TABLE t_library_status (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name varchar(64) NOT NULL UNIQUE, descr varchar(255) NOT NULL, sound blob, desc_invoff varchar(255) NOT NULL, desc_off varchar(255) NOT NULL, desc_on varchar(255) NOT NULL, desc_invon varchar(255) NOT NULL, sound_invoff blob, sound_off blob, sound_on blob, sound_invon blob)");
    	case dm::os::CDb::DtMysql:
    		return m_db->exec("CREATE TABLE t_library_status (id int(10) NOT NULL AUTO_INCREMENT, name varchar(64) NOT NULL UNIQUE, descr varchar(255) NOT NULL, sound binary(1000), desc_invoff varchar(255) NOT NULL, desc_off varchar(255) NOT NULL, desc_on varchar(255) NOT NULL, desc_invon varchar(255) NOT NULL, sound_invoff binary(1000), sound_off blob, sound_on blob, sound_invon blob, PRIMARY KEY (id))");
    	case dm::os::CDb::DtPg:
    	case dm::os::CDb::DtHgdb:
    		return m_db->exec("CREATE TABLE t_library_status (id SERIAL NOT NULL, name varchar(64) NOT NULL UNIQUE, descr varchar(255) NOT NULL, sound bytea, desc_invoff varchar(255) NOT NULL, desc_off varchar(255) NOT NULL, desc_on varchar(255) NOT NULL, desc_invon varchar(255) NOT NULL, sound_invoff bytea, sound_off bytea, sound_on bytea, sound_invon bytea, PRIMARY KEY (id))");
    	default:
    		return false;
    	}

    }

    bool addALoaded( SStatusInfo& info ){
    	if( info.id>m_maxId )
    		m_maxId = info.id;

    	return true;
    }

    bool filterLoaded(){
        char sql[256];
        if( m_maxId>=0 )
        	std::sprintf(sql,"SELECT id,name,descr,sound,desc_invoff,desc_off,desc_on,desc_invon,sound_invoff,sound_off,sound_on,sound_invon FROM t_library_status where id>%d order by id",m_maxId);
        else
        	std::sprintf(sql,"SELECT id,name,descr,sound,desc_invoff,desc_off,desc_on,desc_invon,sound_invoff,sound_off,sound_on,sound_invon FROM t_library_status order by id");

        m_resultSet = m_db->query(sql);
        return m_resultSet;
    }

    bool next(){
        if( m_resultSet )
            return m_resultSet->next();
        
        return false;
    }

    bool loadRecord( SStatusInfo& record ){
        if( m_resultSet ){
            record.id = m_resultSet->asInt64(0,-1);
            record.name = m_resultSet->asString(1,"");
            record.desc = m_resultSet->asString(2,"");
            record.sound = m_resultSet->asString(3,"");

            record.descInvOff = m_resultSet->asString(4,"");
            record.descOff = m_resultSet->asString(5,"");
            record.descOn = m_resultSet->asString(6,"");
            record.descInvOn = m_resultSet->asString(7,"");
            
            record.soundInvOff = m_resultSet->asString(8,"");
            record.soundOff = m_resultSet->asString(9,"");
            record.soundOn = m_resultSet->asString(10,"");
            record.soundInvOn = m_resultSet->asString(11,"");

            return true;
        }

        return false;
    }

    bool reloadRecord( SStatusInfo& info ){
        char sql[256];
        std::sprintf(sql,"SELECT id,name,descr,sound,desc_invoff,desc_off,desc_on,desc_invon,sound_invoff,sound_off,sound_on,sound_invon FROM t_library_status where id=%d order by id",info.id);
        m_resultSet = m_db->query(sql);

        if( !m_resultSet->next() )
        	return false;
        return loadRecord(info);
    }

private:
    id_t m_maxId;
    dm::TScopedPtr<dm::os::CDb> m_db;
    dm::TScopedPtr<dm::os::CResultSet> m_resultSet;
};

typedef CStatusMgr::buf_mgr_t::CNormalReader reader_t;

CStatusMgr::CStatusMgr():m_bufMgr(logModule){
    log().debug(THISMODULE "创建对象 记录数:%d",m_bufMgr.count());
}

CStatusMgr& CStatusMgr::ins(){
    static CStatusMgr i;
    return i;
}


void CStatusMgr::reset(){
	buf_mgr_t::CUnloader unloader;
    m_bufMgr.remove(unloader);
}

/**
 * 初始化表
 * @return
 */
bool CStatusMgr::init(){
	CLoader loader;
	return loader.createTables();
}

CStatusMgr::pos_t CStatusMgr::first(SStatusInfo& info ){
	reader_t reader;
	return m_bufMgr.first(&info, &reader);
}

CStatusMgr::pos_t CStatusMgr::last( SStatusInfo& info ){
	reader_t reader;
	return m_bufMgr.last(&info,&reader);
}

CStatusMgr::pos_t CStatusMgr::next( const pos_t& pos,SStatusInfo& info ){
	reader_t reader;
	return m_bufMgr.next(pos,&info,&reader);
}

CStatusMgr::pos_t CStatusMgr::previous( const pos_t& pos,SStatusInfo& info ){
	reader_t reader;
	return m_bufMgr.previous(pos,&info,&reader);
}

bool CStatusMgr::loadNews(){
	CLoader loader;
	return m_bufMgr.loadNews(loader);
}

CStatusMgr::pos_t CStatusMgr::loadNew( SStatusInfo& info ){
	CLoader loader;
	reader_t reader;
	return m_bufMgr.loadNew(loader, &info, &reader);
}

bool CStatusMgr::reload( id_t id ){
	buf_mgr_t::CIdFinder finder;
	CLoader loader;
	return m_bufMgr.reload(&id, nullptr, nullptr, finder, loader, nullptr, nullptr, nullptr);
}

bool CStatusMgr::reload( id_t id,pos_t& pos ){
	buf_mgr_t::CIdFinder finder;
	CLoader loader;
	return m_bufMgr.reload(&id, nullptr, nullptr, finder, loader, &pos, nullptr, nullptr);
}

bool CStatusMgr::reload( id_t id,SStatusInfo& info ){
	buf_mgr_t::CIdFinder finder;
	CLoader loader;
	reader_t reader;
	return m_bufMgr.reload(&id, nullptr, nullptr, finder, loader, nullptr, &info, &reader);
}

bool CStatusMgr::reload( id_t id,pos_t& pos,SStatusInfo& info ){
	buf_mgr_t::CIdFinder finder;
	CLoader loader;
	reader_t reader;
	return m_bufMgr.reload(&id, nullptr, nullptr, finder, loader, &pos, &info, &reader);
}

bool CStatusMgr::reload( const pos_t& pos ){
	CLoader loader;
	return m_bufMgr.reload(pos, loader,nullptr,nullptr);
}

bool CStatusMgr::reload( const pos_t& pos,SStatusInfo& info ){
	CLoader loader;
	reader_t reader;
	return m_bufMgr.reload(pos, loader, &info, &reader);
}

bool CStatusMgr::unload( const pos_t& pos ){
	buf_mgr_t::CUnloader unloader;
	return m_bufMgr.unload(pos, unloader);
}

bool CStatusMgr::unload( id_t id ){
	buf_mgr_t::CUnloader unloader;
	buf_mgr_t::CIdFinder finder;
	return m_bufMgr.unload(id, finder, unloader);
}

bool CStatusMgr::unload( const char* name){
	buf_mgr_t::CUnloader unloader;
	buf_mgr_t::CIdFinder finder;
	return m_bufMgr.unload(name, finder, unloader);
}

bool CStatusMgr::find( id_t id,pos_t& pos ){
	buf_mgr_t::CIdFinder finder;
	return m_bufMgr.find(id, finder,pos);
}

bool CStatusMgr::find( id_t id,SStatusInfo& info ){
	buf_mgr_t::CIdFinder finder;
	reader_t reader;
	return m_bufMgr.find(id,finder,&info,reader);
}

bool CStatusMgr::find( id_t id,pos_t& pos,SStatusInfo& info ){
	buf_mgr_t::CIdFinder finder;
	reader_t reader;
	return m_bufMgr.find(id,finder,pos,&info,reader);
}

bool CStatusMgr::find( const char* name,pos_t& pos ){
	buf_mgr_t::CIdFinder finder;
	return m_bufMgr.find(name, finder,pos);
}

bool CStatusMgr::find( const char* name,SStatusInfo& info ){
	buf_mgr_t::CIdFinder finder;
	reader_t reader;
	return m_bufMgr.find(name,finder,&info,reader);
}

bool CStatusMgr::find( const char* name,pos_t& pos,SStatusInfo& info ){
	buf_mgr_t::CIdFinder finder;
	reader_t reader;
	return m_bufMgr.find(name,finder,pos,&info,reader);
}

bool CStatusMgr::get( const pos_t& pos,SStatusInfo& info ){
	reader_t reader;
	return m_bufMgr.get(pos, &info, reader);
}

bool CStatusMgr::get( index_t idx,offset_t offset,pos_t& pos,SStatusInfo& info ){
	return false;
}

}
}
}
